package com.wmm.fast.service;

import com.google.common.base.Preconditions;
import com.wmm.common.Shift;
import com.wmm.common.persistence.CrudMapper;
import com.wmm.common.service.CrudServiceImpl;
import com.wmm.fast.controller.StatusCode;
import com.wmm.fast.domain.Product;
import com.wmm.fast.domain.ProductStockTcc;
import com.wmm.fast.domain.type.TccStatus;
import com.wmm.fast.exception.ReservationExpireException;
import com.wmm.fast.persistence.ProductMapper;
import com.wmm.fast.persistence.ProductStockTccMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.OffsetDateTime;

@Service
public class ProductStockTccService extends CrudServiceImpl<ProductStockTcc> {

    @Autowired
    public ProductStockTccService(CrudMapper<ProductStockTcc> mapper) {
        super(mapper);
    }

    @Autowired
    private ProductService productService;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductStockTccMapper tccMapper;


    public ProductStockTcc trying(Long productId) {
        return trying(productId, 15);
    }

    private ProductStockTcc trying(Long productId, long expireSeconds) {
        Preconditions.checkArgument(productId > 0);
        final Product product = productService.find(productId);
        if (product == null) {
            Shift.fatal(StatusCode.PRODUCT_NOT_EXISTS);
        }
        return trying(product, expireSeconds);
    }

    @Transactional(rollbackFor = Exception.class)
    public ProductStockTcc trying(Product product, long expireSeconds) {
        Preconditions.checkNotNull(product);
        Preconditions.checkNotNull(product.getId());
        Preconditions.checkArgument(expireSeconds > 0);
        //预占一个库存单位
        final int isLock = productMapper.consumeStock(product.getId());
        if (isLock == 0)
            Shift.fatal(StatusCode.INSUFFICIENT_PRODUCT);
        final ProductStockTcc tcc = new ProductStockTcc();
        //默认一个库存数量
        tcc.setStock(1);
        tcc.setStatus(TccStatus.TRY);
        tcc.setProductId(product.getId());
        tcc.setExpireTime(OffsetDateTime.now().plusSeconds(expireSeconds));
        persistNonNullProperties(tcc);
        return tcc;
    }

    @Transactional(rollbackFor = Exception.class)
    public void confirmReservatoin(Long reservationId) {
        Preconditions.checkNotNull(reservationId);
        final ProductStockTcc stockTcc = super.find(reservationId);
        //获取不到记录说明已经被补偿或者已过期、不存在。
        if (stockTcc == null) {
            throw new ReservationExpireException("resource `" + reservationId + "` has been cancelled or does not exists at all");
        }
        //确认tcc状态，如果是try则进行confirm
        if (stockTcc.getStatus() == TccStatus.TRY) {
            final int isSuccessful = tccMapper.updateToConfirmationById(reservationId);
            if (isSuccessful == 0) {
                //如果执行此逻辑说明资源已经被撤销
                throw new ReservationExpireException("resource `" + reservationId + "` has been cancelled");
            }
        }

    }
}
